/**
 * 简单来说就是 个容器，里面保存着某个未来才会结束的事件（通常是异步操作）的结果。
 * promise：pending => fulfilled / rejected
 * 可以将异步操作以同步操作的流程表达出来，避免了层层嵌套的回调函数
 *
 * 缺点：首先，无法取消 Promise 一旦新建它就会立即执行，无法中途取消。
 * 其次，如果不设置回调函数， Promise 内部抛出的错误不会反应到外部
 * 再者，当处于 Pending状态时，无法得知目前进展到哪 个阶段（刚刚开始还是即将完成）。
 */

/** promise实现图片懒加载
 * 使用 Promise 包装了 个图片加载的异步操作 如果加载成功，就调用resolve 方法，否则就调用 reject 方法。
 * @param url
 * @returns {Promise<unknown>}
 */
function lazyLoadImage(url) {
  return new Promise((resolve, reject) => {
    let image = new Image()
    image.onload = function () {
      resolve(image)
    }
    image.onerror = function () {
      reject(new Error("Dont load image at :" + url))
    }
    image.src = url
  })
}

/**
 * 使用promise封装一个ajax
 *
 */

function getJSON(url) {
  let promise = new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest()
    xhr.open("GET", url, true)

    // 状态监听
    xhr.onreadystatechange = function () {
      if (this.readyState !== 4) return

      if (this.status === 200) {
        resolve(this.response)
      } else {
        reject(new Error(this.statusText))
      }
    }

    // 错误监听
    xhr.onerror = function () {
      reject()
    }

    xhr.responseType = 'json'
    xhr.setRequestHeader('Accept', 'application/json')

    xhr.send(null)
  })

  return promise
}


/**
 * then 是 promise 原型对象上的方法
 * then 方法的第一个参数是 Resolved 态的回调函数，第二个参数（可选）是 Rejecte 状态的回调函数。
 * then 方法返回的是一个新的 Promise 实例（注意，不是原来那个 Promise 实例）
 */
getJSON('/posts.json').then(
    post => getJSON(post.commentURL) // 返回一个新的promise
).then(
    comments => console.log("Resolved:", comments), // 新的promise状态为成功时
    err => console.log("Rejected:", err)  // 新的promise状态为失败时
)


/**
 * 如果没有catch指定错误回调的函数，Promise抛出的错误不会传递到外部，即对错误没有任何反应
 * Promise.prototype.catch 方法是 then(null, rejection ）的别名，用于指定发生错误时的回调函数。
 */
getJSON('/post/1')
    .then(
        res => console.log(res)  // 返回成功
    )
    .catch(error => {
      // 处理 getJSON和前一个回调函数运行时发生的错误
      console.log(error)  // 返回失败
    })
    .finally(() => {
      console.log("finally")
    })

// finally 方法用于指定不管 Promise 象最后状态如何都会执行的操作。
